package org.apcs.pokemon.pokemon;

/**
 * Author:			Zachary Reed
 * Date Created:	Mar 24, 2010
 * Last Modified:	Mar 31, 2010
 * Package:			org.apcs.pokemon.pokemon
 * Filename:		Pokemon.java
 * Description:		A superclass that stores the data of individual pokemon &
 * 					provides methods to access & alter each.
 */

import java.util.Random;
import org.apcs.pokemon.mechanics.Experience;
import org.apcs.pokemon.mechanics.Move;

public class Pokemon {

	private int intNumber;
	private String strName;							// Pokemon name
    private boolean blnHasNickname;
	private int intGender;							// Pokemon gender 0=male,1=female,2=none
	private int[] arrTypes = new int[2];			// Type(s) of pokemon
	private int intHP;								// Current HP
    private int[] arrStats = new int[6];            // Pokemon's stats
	private int[] arrBaseStats = new int[6];		// Base stats of pokemon's species
    private int[] arrIVs = new int[6];              // Pokemon's stat modifiers ("genes")
	private int[] arrEVYield = new int[7];			// Effort points awarded per stat (+exp)
	private int[] arrEVs = new int[6];              // Total effort points earned per stat
	private int intExpTotal;						// Total experience points
	private int intExpThisLvl;						// Experience points earned this level
	private int intExpNextLvl;						// Experience points needed to reach next level
	private int intExpType;							// Experience type
	private int intEvolveLevel;						// Level pokemon evolves
	private int intEvolveNum;						// Number of pokemon evolved into
	private int intLevel;							// Current level
	private int intStatus;							// 0=None,1-7=Sleep,8=Poison,9=Burn,10=Frozen,11=Bad Poison
	private int intTrainerID;						// Trainer's ID
	private Move[] arrMoves = new Move[4];			// Current moves
    private int[][] arrLvlUpMoves;
    private int[] arrTMHMMoves;

	private static final Random rand = new Random();

	/* Only used to define individual species, not used to create actual pokemon */
	protected Pokemon(int number,String name,boolean isnickname,int gender,int[] type,int[] stats,int[] evyield,
			int exptype,int evolvelvl,int evolvenum,int trainerID,int[] moves,int[][] lvlupmoves,int[] tmhmmoves) {
			intNumber = number;
			strName = name;
            blnHasNickname = isnickname;
			arrTypes[0] = type[0];
			arrTypes[1] = type[1];
			arrBaseStats = stats;
			intHP = arrBaseStats[0];
			arrEVYield = evyield;
			intEvolveLevel = evolvelvl;
			intEvolveNum = evolvenum;
			intExpType = exptype;
			intLevel = 5;
			intExpTotal = Experience.calcExperience(intLevel,intExpType);
			intExpThisLvl = 0;
			intExpNextLvl = Experience.calcExperience(intLevel + 1,intExpType);
			intTrainerID = trainerID;
            genIVs();
            calcStats();

			if (moves[0] != -1) {
				for (int i=0;i<moves.length;i++) {arrMoves[i] = new Move(moves[i]);}
				for (int i=moves.length;i<4;i++) {arrMoves[i] = new Move(0);}
			}
			else {for (int i=0;i<4;i++) {arrMoves[i] = new Move(0);}}
	}

	/* Only used to define individual species, not used to create actual pokemon (custom level)*/
	protected Pokemon(int number,String name,boolean isnickname,int level,int gender,int[] type,int[] stats,int[] evyield,
			int exptype,int evolvelvl,int evolvenum,int trainerid,int[] moves,int[][] lvlupmoves,int[] tmhmmoves) {
			intNumber = number;
			strName = name;
            blnHasNickname = isnickname;
			arrTypes[0] = type[0];
			arrTypes[1] = type[1];
			arrBaseStats = stats;
			intHP = arrBaseStats[0];
			arrEVYield = evyield;
			intEvolveLevel = evolvelvl;
			intEvolveNum = evolvenum;
			intExpType = exptype;
			intLevel = level;
			intExpTotal = Experience.calcExperience(intLevel,intExpType);
			intExpThisLvl = 0;
			intExpNextLvl = Experience.calcExperience(intLevel + 1,intExpType);
			intTrainerID = trainerid;
            genIVs();
            calcStats();

			int movecount = moves.length;
			for (int i=0;i<movecount;i++) {arrMoves[i] = new Move(moves[i]);}
			for (int i=movecount;i<4;i++) {arrMoves[i] = new Move(0);}
	}

    /* Used to create actual pokemon */
    public static final Pokemon createPokemon(int num, int trainerID) {
        switch (num) {
            case 1: return (new Bulbasaur(trainerID));
            case 2: return (new Ivysaur(trainerID));
            case 3: return (new Venusaur(trainerID));
            case 4: return (new Charmander(trainerID));
            case 5: return (new Charmeleon(trainerID));
            case 6: return (new Charizard(trainerID));
            case 7: return (new Squirtle(trainerID));
            case 8: return (new Wartortle(trainerID));
            case 9: return (new Blastoise(trainerID));
            default: return null;
        }
    }

	/* Get the pokemon's name/nickname. */
	public final String name() {return strName;}

	/* Get the pokemon's gender. */
	public final int gender() {return intGender;}

	/* Get the pokemon's trainer's ID. */
	public final int trainerID() {return intTrainerID;}

	/* Get the pokemon's types. */
	public final int type1() {return arrTypes[0];}
	public final int type2() {return arrTypes[1];}

    /* Get the pokemon's current level. */
    public final int level() {return intLevel;}

    /* Get the pokemon's stats. */
    public final int HP() {return arrStats[0];}
    public final int AT() {return arrStats[1];}
    public final int DE() {return arrStats[2];}
    public final int SA() {return arrStats[3];}
    public final int SD() {return arrStats[4];}
    public final int SP() {return arrStats[5];}

    /* Get the pokemon's current HP */
    public final int currentHP() {return intHP;}

    /* Get the pokemon's total experience */
    public final int expTotal() {return intExpTotal;}

    /* Get experience needed for pokemon to level up */
    public final int expNextLvl() {return intExpNextLvl;}

	/* Get one of the pokemon's moves by index. */
	public final Move move(int index) {return arrMoves[index];}

	/* Increase effort points earned by num. */
	public final void incHPEffortPts(int num) {arrEVs[0]+= num;}
	public final void incATEffortPts(int num) {arrEVs[1]+= num;}
	public final void incDEEffortPts(int num) {arrEVs[2]+= num;}
	public final void incSAEffortPts(int num) {arrEVs[3]+= num;}
	public final void incSDEffortPts(int num) {arrEVs[4]+= num;}
	public final void incSPEffortPts(int num) {arrEVs[5]+= num;}

	/* Increase pokemon's experince by num, check if it has enough to level up */
	public final void addExperience(int num) {
		intExpTotal += num;
		intExpThisLvl += num;
		while (intExpThisLvl >= intExpNextLvl) {levelUp();}
	}

    /* Increase current HP by num. */
    public final void addHP(int num) {intHP += num;}

    /* Restore current HP to max HP */
    public final void restoreHP() {intHP = arrStats[0];}

    /* Increment the pokemon's level, and evolve or attempt to learn move if necessary */
	private final void levelUp() {
		intLevel++;
        intExpThisLvl = (intExpThisLvl - intExpNextLvl);
        intExpNextLvl = Experience.calcExperience(intLevel + 1,intExpType);
        calcStats();
		//if (intLevel >= intEvolveLevel) {evolve(intEvolveNum);}
		// check if able to learn new move
	}

    /* Evolve pokemon into its next form */
	private final void evolve() {
        // Confirm player wants pokemon to evolve
		switch (intEvolveNum) {
            case 2:
                if (!blnHasNickname) {strName = Ivysaur.NAME;}
                intNumber = Ivysaur.NUMBER;
                arrTypes = Ivysaur.TYPES;
                arrEVYield = Ivysaur.EVYIELDS;
                intEvolveLevel = Ivysaur.EVOLVES_AT_LVL;
                intEvolveNum = Ivysaur.EVOLVES_INTO;
                arrLvlUpMoves = Ivysaur.LEVEL_UP_MOVES;
                arrTMHMMoves = Ivysaur.TMHM_MOVES;

                for (int i=0;i<Ivysaur.BASE_MOVES.length;i++) {
                    if (Ivysaur.BASE_MOVES[i] != -1) {learnMove(Ivysaur.BASE_MOVES[i]);}
                }
		}
	}

    /* Attempt to learn a new move */
    private final void learnMove(int move) {
        boolean learned = false;
        for (int i=0;i<4;i++) {
            if (arrMoves[i].getName().equals("-")) {
                arrMoves[i] = new Move(move);
                learned = true;
                break;
            }
        }
        if (!learned) {
            // No open move slots, prompt player to replace move or not
        }
    }

	/* Calculate pokemon's gender using M/F ratio (only used when creating pokemon.) */
	protected static final int calcGender(double mfratio) {
		if (mfratio == 100.0) {return 0;}
		else if (mfratio == 0.0) {return 1;}
		else if (mfratio == 255.0) {return 2;}
		else {
			int result = (rand.nextInt(101));
			if (result > (mfratio*100)) {return 0;}
			else {return 1;}
		}
	}

    /* (Re)Calculates a pokemon's stats */
    private final void calcStats() {
        
        arrStats[0] = (int)Math.floor((arrIVs[0]+(2*arrBaseStats[0])+(arrEVs[0]/4))*((double)intLevel/100)+(intLevel + 10));
        arrStats[1] = (int)Math.floor((arrIVs[1]+(2*arrBaseStats[1])+(arrEVs[1]/4))*((double)intLevel/100)+5);
        arrStats[2] = (int)Math.floor((arrIVs[2]+(2*arrBaseStats[2])+(arrEVs[2]/4))*((double)intLevel/100)+5);
        arrStats[3] = (int)Math.floor((arrIVs[3]+(2*arrBaseStats[3])+(arrEVs[3]/4))*((double)intLevel/100)+5);
        arrStats[4] = (int)Math.floor((arrIVs[4]+(2*arrBaseStats[4])+(arrEVs[4]/4))*((double)intLevel/100)+5);
        arrStats[5] = (int)Math.floor((arrIVs[5]+(2*arrBaseStats[5])+(arrEVs[5]/4))*((double)intLevel/100)+5);
    }

    /* Generate pokemon's IV's (only used when creating pokemon.) */
    private final void genIVs() {
        for (int i=0;i<6;i++) {arrIVs[i] = rand.nextInt(32);}
    }
}
